import java.io.*;
import java.util.GregorianCalendar;


public class Main {
	
	private static final int ANZAHL_VERSUCHE = 10;
	public static int EVOLUTIONSDAUER = 10; //in Sekunden, pro Agent
	private static GUI gui;
	
	private static Agent[] agenten;
	private static Hindernis[] hindernisse;

	/**
	 * @param args 1. Stelle ist Aufgabenteil, 2. Stelle ist Eingabedatei
	 */
	public static void main(String[] args) {
		gui = new GUI(args[0]);
		String filename = args[1]; 
		String zeile;
		String[] daten;
		try {
			BufferedReader in = new BufferedReader(new FileReader(filename));
			zeile = in.readLine();
			hindernisse = new Hindernis[Integer.parseInt(zeile)];
			for (int i = 0; i < hindernisse.length; i++){
				zeile = in.readLine();
				daten = zeile.split(" ");
				hindernisse[i] = Hindernis.createHindernis(daten);
			}
			zeile = in.readLine();
			agenten = new Agent[Integer.parseInt(zeile)];
			for (int i = 0; i < agenten.length; i++){
				zeile = in.readLine();
				daten = zeile.split(" ");
				agenten[i] = Agent.createAgent(daten, gui);
			}
			if (args[0].equals("a")){
				a();
			} else if (args[0].equals("b")){
				b();
			} else if (args[0].equals("c")){
				c();
			} else if (args[0].equals("d")){
				d();
			}
		} catch (Exception e){
			System.out.println(e);
		}
		
	}
	
	public static void a(){
		einfacheBewegung(agenten, hindernisse, 0);
	}
	
	public static void b(){
		einfacheBewegung(agenten, hindernisse, 1);
	}
	
	public static void c(){
		evolutionaereBewegung(agenten, hindernisse, false);
	}
	
	public static void d(){
		evolutionaereBewegung(agenten, hindernisse, true);
	}
	
	private static void einfacheBewegung(Agent[] agenten, Hindernis[] hindernisse, int beschleunigung){
		boolean erfolg;
		for (int i = 0; i < agenten.length; i++){
			erfolg = agenten[i].moveTo(agenten[i].getZielX(), agenten[i].getZielY(), 
					beschleunigung, hindernisse);
			if (erfolg) {
				System.out.println("Agent Nummer " + (i + 1) + " erreicht Ziel in " + 
						agenten[i].getAktuelleZeit() + " Sekunden." );
				gui.mw.infoArea.append("\nAgent Nummer " + (i + 1) + " erreicht Ziel in " + 
						agenten[i].getAktuelleZeit() + " Sekunden.");
			} else {
				System.out.println("Agent Nummer " + (i + 1) + " wird von Hindernis erwischt");
				gui.mw.infoArea.append("\nAgent Nummer " + (i + 1) + " wird von Hindernis erwischt");
			}
		}
	}
	
	private static void evolutionaereBewegung(Agent[] agenten, Hindernis[] hindernisse, boolean randomDirection){
		//System.out.println("evo-action");
		Agent[] agentenEvo = new Agent[ANZAHL_VERSUCHE + 1];
		int verliererIndex = ANZAHL_VERSUCHE; // Index des Agenten, der als n�chstes �berschrieben wird
		int versuchsIndex = 0; //Index des Agenten, bei dem aktuell probiert wird
		int fitness1 = 0;
		int fitness2 = 0;
		boolean erfolg = false;
		double bestzeit = Double.MAX_VALUE; //Bestzeit eines Weges zum Ziel
		int agentenIndex = 0;
		GregorianCalendar kalender = null;
		for (Agent agent : agenten){
			agentenIndex++;
			bestzeit = Double.MAX_VALUE;
			//kopiere Agenten in Array
			for (int i = 0; i < agentenEvo.length; i++){
				agentenEvo[i] = agent.copy();
			}
			//wiederhole f�r gewisse Zeit
			kalender = new GregorianCalendar();
			kalender.add(GregorianCalendar.SECOND, EVOLUTIONSDAUER);
			while (new GregorianCalendar().before(kalender)){
//				System.out.println("n�chste Runde");
				//w�hle n�chsten Versuch zuf�llig, w�hle nicht Verlierer
				versuchsIndex = (int) Math.random() * ANZAHL_VERSUCHE;
				if (versuchsIndex >= verliererIndex){
					versuchsIndex++;
				}
				agentenEvo[verliererIndex] = agentenEvo[versuchsIndex].copy();
//				System.out.println("gleich wird bewegt");
				erfolg = agentenEvo[verliererIndex].moveToRandomPoint(hindernisse, randomDirection);
//				System.out.println("es wurde bewegt");
				//bei Misserfolg entsprechende Variable hochz�hlen
				if (!erfolg || agentenEvo[verliererIndex].getBestzeit() >= bestzeit){
					agentenEvo[versuchsIndex].incFehlschlag();
				} else {
					//pr�fe ob Agent Ziel erreicht hat
					if (agentenEvo[verliererIndex].zielErreicht()){
						bestzeit = agentenEvo[verliererIndex].getAktuelleZeit();
//						System.out.println("angekommen, neue Bestzeit: " + bestzeit);
						for (int i = 0; i < agentenEvo.length; i++){
							//alle dies nicht mehr schaffen k�nnen werden neu gestartet
							if (agentenEvo[i].getBestzeit() <= bestzeit){
								agentenEvo[i] = agent.copy();
							}
						}
					}
					
//					System.out.println("gleich kommt fitness");
					//w�hle 2 zuf�llige verschiedene Kandidaten
					fitness1 = (int)Math.random() * (ANZAHL_VERSUCHE + 1);
					fitness2 = (int)Math.random() * ANZAHL_VERSUCHE;
					if (fitness2 >= fitness1){
						fitness2++;
					}
					
					//der schlechtere der beiden wird neuer Verlierer
					if (agentenEvo[fitness1].getFitness() > agentenEvo[fitness2].getFitness()){
						verliererIndex = fitness1;
					} else {
						verliererIndex = fitness2;
					}
				}
//				System.out.println("Runde durch");
			}
//			System.out.println("Die Bestzeit ist " + (int) agent.getBestzeit());
//			System.out.println("Agent Nummer " + (agentenIndex) + " erreicht Ziel in " + 
//					(int) bestzeit + " Sekunden.");
			if (bestzeit < Double.MAX_VALUE){
				gui.mw.infoArea.append("\nAgent Nummer " + (agentenIndex) + " erreicht Ziel in " + 
						bestzeit + " Sekunden.");
			} else {
				gui.mw.infoArea.append("\nAgent Nummer " + (agentenIndex) +
						" erreicht das Ziel nicht.");
			}
			gui.mw.btnRestart.setEnabled(true);
		}
	}
}